﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
namespace Book_of_Shadow_Script.Scripts
{
    public class OutText
    {
        public Int64 offset;
        public Int32 len;
        public String text;
        public OutText(Int64 offset, Int32 len, String text)
        {
            this.offset = offset;
            this.len = len;
            this.text = text;
        }
    }
    abstract class ScriptDetail
    {
        public static ScriptDetail GetScript(ScriptFormat sf, long offset, int order, CustomEncoding en = null)
        {
            switch (sf)
            {
                case ScriptFormat.BookOfShadows: return new BookofShadowDetail(offset,order,en);
                case ScriptFormat.Oreimou: return new oreimou2bDetail(offset,order,en);
            }
            throw new Exception("Invaild filter type");
        }
        public long Offset { get { return offset; } }
        public int Order { get { return order; } }
        protected Byte[] head;
        protected ArrayList outtexts = new ArrayList();
        private long offset;
        private int order;
        //private long buflen;
        public Byte[] buf=new Byte[1024];
        protected String text="";
        private CustomEncoding en;//自定义码表
        public ScriptDetail(long offset,int order,CustomEncoding en = null)
        {
            this.order = order;
            this.offset = offset;
            this.en = en;
        }
        protected int Byte2Int(int offset, int len)
        {
            int ret = 0;
            for (int i = offset + len - 1; i >= offset; i--)
            {
                ret <<= 8;
                ret += buf[i];
            }
            return ret;
        }

        public abstract int len();

        public abstract string DisplayByte();
        public string DisplayText()
        {
            return text;
        }
        public abstract int ScpType();
        public void SetOffset(long offset)
        {
            this.offset=offset;
        }
        public abstract void analyze(FileStream fs);
        protected String ReadFileString(FileStream fs, long oft, ref Int32 len)
        {
            int i = 0;
            String ret;
            long pos = fs.Position;
            Byte[] textbuf = new Byte[256];
            fs.Seek(oft, SeekOrigin.Begin);
            do
            {
                textbuf[i] = (Byte)fs.ReadByte();
            } while (textbuf[i++] > 0);
            len = i - 1;

            if (this.en == null)
                ret = Encoding.GetEncoding(932).GetString(textbuf);
            else
                ret = en.GetString(textbuf);
            i = 0;
            while (ret[i] != '\0') i++;
            ret = ret.Substring(0, i);
            fs.Seek(pos, SeekOrigin.Begin);
            return ret;
        }
        public abstract String TextOut();

        public abstract bool hasText();
        public abstract void ReadHead(FileStream fs);
    }
    class Script
    {
        public ArrayList operation = new ArrayList();
        public void ReadFile(FileStream fs,ScriptFormat sf, CustomEncoding en = null)
        {
            int order = 1;
            ScriptDetail sd=ScriptDetail.GetScript(sf,0,0,en);
            sd.ReadHead(fs);
            do
            {
                sd = ScriptDetail.GetScript(sf, fs.Position,order++);
                if (sd is Scripts.BookofShadowDetail)
                {
                    fs.Read(sd.buf, 0, 2);
                    if (sd.len() > 2) fs.Read(sd.buf, 2, sd.len() - 2);
                    operation.Add(sd);
                    sd.analyze(fs);
                    if (sd.buf[0] == 0x0d && sd.buf[1] == 0x02) break;
                }
                else if (sd is oreimou2bDetail)
                {
                    fs.Read(sd.buf, 0, 4);
                    if (sd.len() > 4)
                    {
                        fs.Read(sd.buf, 4, sd.len() - 4);
                        operation.Add(sd);
                        sd.analyze(fs);
                    }
                    else break;
                }
            } while (fs.CanRead);
        }
        public void TextExport(StreamWriter sw)
        {
            //int filepos=0x10;
            Int32 i=0;
            foreach (ScriptDetail sd in operation)
            {
                if (!sd.hasText()) continue;
                i++;
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("{0:D}:", i);
                sb.Append(Environment.NewLine);
                sb.Append(sd.TextOut());
                sb.Append(Environment.NewLine);
                sw.Write(sb.ToString());
            }
        }
    }
}
